/**
 * 测试工具类
 * 提供通用的测试辅助函数
 */

const axios = require('axios');
const fs = require('fs-extra');
const path = require('path');
const chalk = require('chalk');
const moment = require('moment');

class TestUtils {
  constructor(config) {
    this.config = config;
    this.authToken = null;
    this.testResults = [];
    this.startTime = Date.now();
  }

  /**
   * 创建HTTP客户端
   */
  createHttpClient() {
    const client = axios.create({
      baseURL: this.config.server.baseUrl,
      timeout: this.config.server.timeout,
      headers: {
        'Content-Type': 'application/json'
      }
    });

    // 请求拦截器 - 添加认证token
    client.interceptors.request.use((config) => {
      if (this.authToken) {
        config.headers.Authorization = `Bearer ${this.authToken}`;
      }
      return config;
    });

    // 响应拦截器 - 处理错误
    client.interceptors.response.use(
      (response) => response,
      (error) => {
        console.error(chalk.red(`HTTP请求失败: ${error.message}`));
        if (error.response) {
          console.error(chalk.red(`状态码: ${error.response.status}`));
          console.error(chalk.red(`响应数据: ${JSON.stringify(error.response.data, null, 2)}`));
        }
        return Promise.reject(error);
      }
    );

    return client;
  }

  /**
   * 设置认证token
   */
  setAuthToken(token) {
    this.authToken = token;
  }

  /**
   * 清除认证token
   */
  clearAuthToken() {
    this.authToken = null;
  }

  /**
   * 等待指定时间
   */
  async sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * 重试执行函数
   */
  async retry(fn, maxAttempts = 3, delay = 1000) {
    let lastError;
    
    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
      try {
        return await fn();
      } catch (error) {
        lastError = error;
        console.warn(chalk.yellow(`尝试 ${attempt}/${maxAttempts} 失败: ${error.message}`));
        
        if (attempt < maxAttempts) {
          await this.sleep(delay);
        }
      }
    }
    
    throw lastError;
  }

  /**
   * 记录测试结果
   */
  recordTestResult(testName, module, status, duration, error = null, description = '') {
    const result = {
      name: testName,
      module: module,
      status: status, // 'passed', 'failed', 'skipped'
      duration: duration,
      error: error,
      description: description,
      timestamp: new Date().toISOString()
    };
    
    this.testResults.push(result);
    
    // 实时输出测试结果
    const statusColor = status === 'passed' ? chalk.green : 
                       status === 'failed' ? chalk.red : chalk.yellow;
    
    console.log(`${statusColor(status.toUpperCase())} ${testName} (${duration}ms)`);
    if (error) {
      console.log(chalk.red(`  错误: ${error}`));
    }
  }

  /**
   * 生成随机字符串
   */
  generateRandomString(length = 8) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let result = '';
    for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return result;
  }

  /**
   * 生成测试用户数据
   */
  generateTestUser() {
    const randomSuffix = this.generateRandomString(6);
    return {
      username: `test_user_${randomSuffix}`,
      email: `test_${randomSuffix}@example.com`,
      password: 'Test123456!'
    };
  }

  /**
   * 生成测试任务数据
   */
  generateTestTask(listId = null) {
    const titles = [
      '完成项目文档',
      '准备会议材料',
      '回复客户邮件',
      '更新系统配置',
      '测试新功能',
      '整理工作笔记'
    ];
    
    const priorities = ['high', 'medium', 'low'];
    const tags = ['工作', '重要', '紧急', '学习', '个人'];
    
    return {
      title: titles[Math.floor(Math.random() * titles.length)] + ` ${this.generateRandomString(4)}`,
      description: `这是一个测试任务 - ${this.generateRandomString(8)}`,
      priority: priorities[Math.floor(Math.random() * priorities.length)],
      listId: listId,
      dueDate: new Date(Date.now() + Math.random() * 7 * 24 * 60 * 60 * 1000).toISOString(),
      tags: [tags[Math.floor(Math.random() * tags.length)]],
      completed: false
    };
  }

  /**
   * 生成测试清单数据
   */
  generateTestList() {
    const names = [
      '工作任务',
      '个人事务',
      '学习计划',
      '购物清单',
      '旅行计划',
      '健身目标'
    ];
    
    const colors = ['#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6', '#06b6d4'];
    
    return {
      name: names[Math.floor(Math.random() * names.length)] + ` ${this.generateRandomString(4)}`,
      description: `测试清单 - ${this.generateRandomString(8)}`,
      color: colors[Math.floor(Math.random() * colors.length)]
    };
  }

  /**
   * 验证API响应格式
   */
  validateApiResponse(response, expectedFields = []) {
    if (!response || !response.data) {
      throw new Error('API响应格式无效: 缺少data字段');
    }
    
    for (const field of expectedFields) {
      if (!(field in response.data)) {
        throw new Error(`API响应格式无效: 缺少必需字段 ${field}`);
      }
    }
    
    return true;
  }

  /**
   * 验证任务对象格式
   */
  validateTaskObject(task) {
    const requiredFields = ['id', 'title', 'completed'];
    for (const field of requiredFields) {
      if (!(field in task)) {
        throw new Error(`任务对象格式无效: 缺少必需字段 ${field}`);
      }
    }
    return true;
  }

  /**
   * 验证清单对象格式
   */
  validateListObject(list) {
    const requiredFields = ['id', 'name'];
    for (const field of requiredFields) {
      if (!(field in list)) {
        throw new Error(`清单对象格式无效: 缺少必需字段 ${field}`);
      }
    }
    return true;
  }

  /**
   * 获取测试统计信息
   */
  getTestStatistics() {
    const total = this.testResults.length;
    const passed = this.testResults.filter(r => r.status === 'passed').length;
    const failed = this.testResults.filter(r => r.status === 'failed').length;
    const skipped = this.testResults.filter(r => r.status === 'skipped').length;
    const duration = Date.now() - this.startTime;
    
    return {
      total,
      passed,
      failed,
      skipped,
      successRate: total > 0 ? (passed / total * 100).toFixed(1) : 0,
      duration
    };
  }

  /**
   * 打印测试摘要
   */
  printTestSummary() {
    const stats = this.getTestStatistics();
    
    console.log('\n' + chalk.bold('='.repeat(60)));
    console.log(chalk.bold.cyan('                    测试执行摘要'));
    console.log(chalk.bold('='.repeat(60)));
    console.log(`总测试数: ${chalk.bold(stats.total)}`);
    console.log(`通过: ${chalk.green.bold(stats.passed)}`);
    console.log(`失败: ${chalk.red.bold(stats.failed)}`);
    console.log(`跳过: ${chalk.yellow.bold(stats.skipped)}`);
    console.log(`成功率: ${chalk.bold(stats.successRate)}%`);
    console.log(`总耗时: ${chalk.bold(stats.duration)}ms`);
    console.log(chalk.bold('='.repeat(60)));
    
    if (stats.failed > 0) {
      console.log('\n' + chalk.red.bold('失败的测试:'));
      this.testResults
        .filter(r => r.status === 'failed')
        .forEach(result => {
          console.log(chalk.red(`  ✗ ${result.name}: ${result.error}`));
        });
    }
  }

  /**
   * 清理测试数据
   */
  async cleanupTestData(httpClient) {
    console.log(chalk.yellow('开始清理测试数据...'));
    
    try {
      // 这里可以添加清理逻辑，比如删除测试创建的任务和清单
      // 注意：需要根据实际API接口来实现
      console.log(chalk.green('测试数据清理完成'));
    } catch (error) {
      console.warn(chalk.yellow(`清理测试数据时出现警告: ${error.message}`));
    }
  }

  /**
   * 格式化时间
   */
  formatTime(timestamp) {
    return moment(timestamp).format('YYYY-MM-DD HH:mm:ss');
  }

  /**
   * 确保目录存在
   */
  async ensureDir(dirPath) {
    await fs.ensureDir(dirPath);
  }

  /**
   * 保存测试结果到文件
   */
  async saveTestResults(filename) {
    const reportDir = this.config.reporting.outputDir;
    await this.ensureDir(reportDir);
    
    const filePath = path.join(reportDir, filename);
    const data = {
      summary: this.getTestStatistics(),
      results: this.testResults,
      config: {
        baseUrl: this.config.server.baseUrl,
        timestamp: new Date().toISOString()
      }
    };
    
    await fs.writeJson(filePath, data, { spaces: 2 });
    console.log(chalk.green(`测试结果已保存到: ${filePath}`));
  }
}

module.exports = TestUtils;